﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ApmetrixDLL
{
    /**
        * ApmetrixEvent
        * Note: limit access control for this class to package-private
        */
    abstract class ApmetrixEvent
    {
        protected static readonly string TAG = "Apmetrix SDK / Event";
        protected static readonly int START_SESSION_EVENT = 0;
        protected static readonly int RESTART_SESSION_EVENT = 1;
        protected static readonly int APPLICATION_EVENT = 2;
        protected static readonly int END_SESSION_EVENT = 3;
        protected static readonly int START_TIMER_EVENT = 4;
        protected static readonly int STOP_TIMER_EVENT = 5;
        protected static readonly int PAUSE_TIMER_EVENT = 6;
        protected static readonly int RESUME_TIMER_EVENT = 7;

        protected Dictionary<string, string> eventData;
        protected int eventType;
        protected ApmetrixSession session;


        /**
        * Constructor for Start, Restart and End Session Events and Application
        * Events that don't use a pre-defined event name
        * @param type of event
        */
        protected internal ApmetrixEvent(int type, ApmetrixSession sessionId)
            : this(type, sessionId, null)
        {

        }

        /**
        * Constructor for Start, Restart and End Session Events and Application
        * Events that use a pre-defined event name
        * @param type of event
        * @param data for event
        */
        protected internal ApmetrixEvent(int type, ApmetrixSession sessionId, Dictionary<string, string> data)
        {
            eventType = type;
            session = sessionId;
            if (type != APPLICATION_EVENT && data == null)
                eventData = new Dictionary<string, string>();
            else if (type == APPLICATION_EVENT && data != null)
                eventData = new Dictionary<string, string>(data);
        }

        /**
         * get event data (varies by event type) 
         */
        abstract protected internal Dictionary<string, string> getEventData();

        /**
         * getter for the gameset ID
         * @return
         */
        public int getGamesetId()
        {
            return session.datasetId;
        }

        /**
         * getter for the game unifier
         * @return
         */
        public string getGameUnifier()
        {
            return session.gameUnifier;
        }

        /**
         * getter for the visitor ID
         * @return
         */
        public string getVisitorId()
        {
            //Test BUild Not Implemented Yet ***************************
            //if (TEST_BUILD)
            //{
            //    if (testAutoTest && testVisitorId != null)
            //        return testVisitorId;
            //    else
            //        return session.visitorId;
            //}
            //else
            return session.visitorId;
        }

        /**
         * getter for the visitor ID
         * @return
         */
        public long getStartSessionTime()
        {
            return session.startSessionTimestamp;
        }



    }

    /**
     * class for the session object
     */
    class ApmetrixSession
    {
        internal long startSessionTimestamp = 0;
        internal string visitorId = null;
        internal int datasetId = -1;
        internal string gameUnifier = null;
        internal string gameVersion = null;

        public ApmetrixSession(int game, String version, String unifier)
        {
            datasetId = game;
            gameVersion = version;
            gameUnifier = unifier;
            startSessionTimestamp = (long)ApmetrixConstants.GetCurrentMilli();
            visitorId = OpenUDIDCSharp.OpenUDID.value;
        }



    }


    /**
     * Class for start session events
     */
    class ApmetrixStartSessionEvent : ApmetrixEvent
    {
        protected internal ApmetrixStartSessionEvent(ApmetrixSession session)
            : base(START_SESSION_EVENT, session)
        {

        }

        protected internal override Dictionary<string, string> getEventData()
        {
            //Not Implemented Yet ***************************
            // get display metrics
            //DisplayMetrics metrics = session.context.getResources().getDisplayMetrics();
            // build screen resolution parameter
            //String screenResolution =  metrics.widthPixels + "x" + metrics.heightPixels;
            // get ISO 639-1 code for this locale's language
            //		String language = 
            //				session.context.getResources().getConfiguration().locale.getLanguage();

            //Need to fix the DEBUG code for PC
            //if (LOG_DEBUG)
            //{
            //    Log.d(TAG, "name of underlying board: " + Build.BOARD);
            //    Log.d(TAG, "system bootloader version number: " + Build.BOOTLOADER);
            //    Log.d(TAG, "the brand: " + Build.BRAND);
            //    Log.d(TAG, "name of native code instruction set: " + Build.CPU_ABI);
            //    Log.d(TAG, "name of second native code instruction set: " + Build.CPU_ABI2);
            //    Log.d(TAG, "name of the industial design: " + Build.DEVICE);
            //    Log.d(TAG, "build ID string: " + Build.DISPLAY);
            //    Log.d(TAG, "unique build identifier: " + Build.FINGERPRINT);
            //    Log.d(TAG, "name of the hardware: " + Build.HARDWARE);
            //    Log.d(TAG, "? Host ? " + Build.HOST);
            //    Log.d(TAG, "Change list number? " + Build.ID);
            //    Log.d(TAG, "the manufacture: " + Build.MANUFACTURER);
            //    Log.d(TAG, "the model: " + Build.MODEL);
            //    Log.d(TAG, "name of overall product: " + Build.PRODUCT);
            //    //			Log.d(TAG, "hardware serial number if available: " + Build.SERIAL);  // not available on NOOK
            //    Log.d(TAG, "tag describing build: " + Build.TAGS);
            //    Log.d(TAG, "? Time ? " + Build.TIME);
            //    Log.d(TAG, "type of build: " + Build.TYPE);
            //    Log.d(TAG, "Value used when build property is unknown: " + Build.UNKNOWN);
            //    Log.d(TAG, "? User ? " + Build.USER);
            //    Log.d(TAG, "Current development code name: " + Build.VERSION.CODENAME);
            //    Log.d(TAG, "Preforce changelist number: " + Build.VERSION.INCREMENTAL);
            //    Log.d(TAG, "User visible version string: " + Build.VERSION.RELEASE);
            //    Log.d(TAG, "User visible sdk version: " + Build.VERSION.SDK_INT);
            //}


            //Needs to be modified for PC instead of Android OS
            if (!eventData.ContainsKey(ApmetrixConstants.Key.TRANSACTION))
                eventData.Add(ApmetrixConstants.Key.TRANSACTION, ApmetrixConstants.Value.START_SESSION);

            if (!eventData.ContainsKey(ApmetrixConstants.Key.BRAND))
                eventData.Add(ApmetrixConstants.Key.BRAND, ApmetrixConstants.Value.BRAND);

            if (!eventData.ContainsKey(ApmetrixConstants.Key.MODEL))
                eventData.Add(ApmetrixConstants.Key.MODEL, ApmetrixConstants.Value.MODEL);

            if (!eventData.ContainsKey(ApmetrixConstants.Key.OPERATING_SYSTEM))
                eventData.Add(ApmetrixConstants.Key.OPERATING_SYSTEM, ApmetrixConstants.Value.OPERATING_SYSTEM);

            if (!eventData.ContainsKey(ApmetrixConstants.Key.BUILD_VERSION))
                eventData.Add(ApmetrixConstants.Key.BUILD_VERSION, ApmetrixConstants.Value.VERSION);

            if (!eventData.ContainsKey(ApmetrixConstants.Key.HARDWARE_TYPE))
                eventData.Add(ApmetrixConstants.Key.HARDWARE_TYPE, ApmetrixConstants.Value.HARDWARE);

            if (!eventData.ContainsKey(ApmetrixConstants.Key.SCREEN_RESOLUTION))
                eventData.Add(ApmetrixConstants.Key.SCREEN_RESOLUTION, ApmetrixConstants.Value.SCREEN_RES);

            if (session.gameVersion != null)
                if (!eventData.ContainsKey(ApmetrixConstants.Key.GAME_VERSION))
                    eventData.Add(ApmetrixConstants.Key.GAME_VERSION, session.gameVersion);
            return eventData;
        }
    }

    /**
    * class for end session events
    */
    class ApmetrixEndSessionEvent : ApmetrixEvent
    {

        protected internal ApmetrixEndSessionEvent(ApmetrixSession session)
            : base(END_SESSION_EVENT, session)
        {

        }

        protected internal override Dictionary<string, string> getEventData()
        {
            if (!eventData.ContainsKey(ApmetrixConstants.Key.TRANSACTION))
                eventData.Add(ApmetrixConstants.Key.TRANSACTION, ApmetrixConstants.Value.END_SESSION);
            if (!eventData.ContainsKey(ApmetrixConstants.Key.END_SESSION))
                eventData.Add(ApmetrixConstants.Key.END_SESSION, "1");
            return eventData;
        }

    }


    /**
     * class for application events
     */
    class ApmetrixApplicationEvent : ApmetrixEvent
    {
        protected internal ApmetrixApplicationEvent(ApmetrixSession session, Dictionary<string, string> eventData)
            : base(APPLICATION_EVENT, session, eventData)
        { }

        protected internal override Dictionary<string, string> getEventData()
        {
            return eventData;
        }
    }


    class ApmetrixTimerEvent : ApmetrixEvent
    {

        protected string tag;
        protected long time;
        protected long duration;

        protected internal ApmetrixTimerEvent(ApmetrixSession session, int eventType)
            : this(session, eventType, null)
        {

        }

        protected internal ApmetrixTimerEvent(ApmetrixSession session, int eventType, String eventTag)
            : base(eventType, session, null)
        {
            tag = eventTag;
            time = (long)ApmetrixConstants.GetCurrentMilli();
            duration = 0;
        }


        protected internal override Dictionary<string, string> getEventData()
        {
            if (!eventData.ContainsKey(ApmetrixConstants.Key.TIMER_EVENT_TAG))
                eventData.Add(ApmetrixConstants.Key.TIMER_EVENT_TAG, tag.ToString());
            if (!eventData.ContainsKey(ApmetrixConstants.Key.TIMER_EVENT_TIME))
                eventData.Add(ApmetrixConstants.Key.TIMER_EVENT_TIME, duration.ToString());
            return eventData;
        }

        /**
         * update event data
         * @param eventType
         * @param eventTag
         * @param eventLength
         * @return true if event data updated, otherwise false
         */
        protected internal void setEventData(long duration)
        {
            this.duration = duration;
        }
    }
}
